<?php
defined('IN_XLP') or die('Access Denied');

/*
 * 微信App接口类 目前只有支付
 */
class weixinApp {
    //获取微信App预支付订单ID链接
    private const PREPAY_URL = "https://api.weixin.qq.com/pay/genprepay?access_token=";
    //微信基本参数
    private $appid;
    private $partner_id;
    private $partner_key;
    private $paysign_key;
    //全局Token
    private $access_token;
    //支付通知URL
    private $notify_url;
    //由开发者自定义，可用于订单的查询与跟踪，建议根据支付用户信息生成此ID
    private $traceid;
    //运行时间
    private $runtime;

    //订单参数
    private $order_params = array();

    public function __construct($params=array()) {

        $this->traceid     = '';
        $this->notify_url  = "U('wxpay/notify/index')";
        $this->runtime     = date('Y-m-d H:i:s', TIME);
        
        $this->appid       = isset($params['appid']) ? $params['appid'] : '';
        $this->partner_id  = isset($params['partner_id']) ? $params['partner_id'] : '';
        $this->partner_key = isset($params['partner_key']) ? $params['partner_key'] : '';
        $this->paysign_key = isset($params['paysign_key']) ? $params['paysign_key'] : '';

        if( !($this->appid && $this->partner_id && $this->partner_key && $this->paysign_key) ) {

            $userInfo = F('weixin/setting');

            if (isHave($userInfo['user_info']['wx_AppId']) 
                && isHave($userInfo['user_info']['wx_PartnerId'])
                && isHave($userInfo['user_info']['wx_PartnerKey'])
                && isHave($userInfo['user_info']['wx_PaySignKey'])) {

                //设置微信基本参数
                $this->appid       = $userInfo['user_info']['wx_AppId'];
                $this->partner_id  = $userInfo['user_info']['wx_PartnerId'];
                $this->partner_key = $userInfo['user_info']['wx_PartnerKey'];
                $this->paysign_key = $userInfo['user_info']['wx_PaySignKey'];

            } else {
                throw new Exception($this->runtime . "Error:请设置好所有的微信参数");
            }
        }

    }


    /*
     * 获取预支付订单ID
     */
    private function getPrepayId() {
        $access_token = $this->getAccessToken();
        $url = self::PREPAY_URL . $access_token;
        
        //生成订单package
        $package = $this->getPackage();
        //生成POST数据
        $json    = $this->getPrepayJSON($package);

        $result  = getHttp($url, $json);
        $res_arr = json_decode($result, true);

        if(isset($res_arr['prepayid'])) {
            return $res_arr['prepayid'];
        } else {
            throw new Exception($this->runtime . ": " . $result);
        }
    }

    /*
     * 获取微信全局AccessToken
     */
    private function getAccessToken() {
        T('weixin/weixin.api');
        $api = new weixinMsgApi();
        $this->access_token = $api->checkAuth();

        if($this->access_token) {
            return $this->access_token;    
        } else {
            throw new Exception($this->runtime . ": fail to get access token");
        }
    }

    /*
     * 生成订单package
     */
    private function getPackage() {
        //已知package字段
        $arr = array(
            'bank_type'        => 'WX',
            'partner'          => $this->partner_id,
            'fee_type'         => '1',
            'notify_url'       => $this->notify_url,
            'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
            'input_charset'    => 'UTF-8'
        );
        //合并订单参数
        $arr = $this->order_params + $arr;
        //排序&签名
        $str1 = '';
        $str2 = '';
        ksort($arr);
        foreach ($arr as $k => $v){
            $str1 .= $k.'='.$v.'&';
            $str2 .= $k.'='.urlencode($v).'&';
        }
        $str1 .= 'key='.$this->partner_key;

        $signValue = strtoupper(md5($str1));
        //最终字符串
        $package   = $str2.'sign='.$signValue;

        return $package;
    }

    /*
     * 生成获取prepayid所需的JSON格式数据
     */
    private function getPrepayJSON($package) {
        
        $noncestr = getRandStr();   //32位以下的随机字符串
        $this->traceid = empty($this->traceid) ? $this->order_params['out_trade_no'] : $this->traceid;
        //待签名参数
        $arr = array(
            "appid"     => $this->appid,
            "appkey"    => $this->paysign_key,
            "noncestr"  => $noncestr,
            "package"   => $package,
            "timestamp" => TIME,
            "traceid"   => $this->traceid,
        );
        //排序&签名
        $sign = $this->getAppSign($arr);
        //最终JSON
        $arr = array(
            "appid"         => $this->appid,
            "traceid"       => $this->traceid,
            "noncestr"      => $noncestr,
            "timestamp"     => TIME,
            "package"       => $package,
            "sign_method"   => "sha1",
            "app_signature" => $sign,
        );

        return json_encode($arr);
    }

    /*
     * 生成App支付参数
     */
    public function getAppParam() {
        $prepayid = $this->getPrepayId();
        $arr = array(
            "appid"     => $this->appid,
            "appkey"    => $this->paysign_key,
            "noncestr"  => getRandStr(),
            "package"   => "Sign=WXpay",
            "partnerid" => $this->partner_id,
            "prepayid"  => $prepayid,
            "timestamp" => TIME+"",
        );
        $sign = $this->getAppSign($arr);
        $arr  = $arr + array("sign"=>$sign);

        unset($arr['appkey']);

        return json_encode($arr); 
    }

    /*
     * 设置订单参数
     */
    public function setOrderParams($data) {
        if(!is_array($data)) {
            throw new Exception($this->runtime . ": order parameter must be an array");
        }
        if( !(  isset($data['body']) 
             && isset($data['out_trade_no']) 
             && isset($data['total_fee']) ) ) {
            throw new Exception($this->runtime . ": missing necessary order parameter");
        }
        $this->order_params = $data;
        return true;
    }

    /*
     * 设置微信支付通知URL
     */
    public function setNotifyURL($url) {
        $this->notify_url = $url;
        return true;
    }
    /*
     * 获取微信支付通知URL
     */
    public function getNofityURL() {
        return $this->notify_url;
    }
    /*
     * 设置traceid
     */
    public function setTraceID($id) {
        $this->traceid = $id;
        return true;
    }
    /*
     * 获取traceid
     */
    public function getTraceID() {
        return $this->traceid;
    }

    /*
     * 字典序sha1签名
     */
    private function getAppSign($arr) {
        $str = '';
        ksort($arr);
        foreach ($arr as $k => $v){
            $str .= strtolower($k).'='.$v.'&';
        }
        return sha1(rtrim($str, '&'));
    }

}